-
Notifications
You must be signed in to change notification settings - Fork 89
tweak(fps): Decouple logic time step from render update #1451
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
2b88c43
to
1036d47
Compare
GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp
Outdated
Show resolved
Hide resolved
You need to update your new 'm_logicTimeScaleFPS' from the game speed option in This will also have a knock on effect that the FPS cap will also need to be increased to match the increased logic rate. GameWindow *sliderGameSpeed = TheWindowManager->winGetWindowFromId( parentSkirmishGameOptions, sliderGameSpeedID );
Int maxFPS = GadgetSliderGetPosition( sliderGameSpeed );
setInt("FPS", maxFPS); |
@@ -100,9 +108,15 @@ class GameEngine : public SubsystemInterface | |||
virtual ParticleSystemManager* createParticleSystemManager( void ) = 0; | |||
virtual AudioManager *createAudioManager( void ) = 0; ///< Factory for Audio Manager | |||
|
|||
Int m_maxFPS; ///< Maximum frames per second allowed | |||
Int m_maxFPS; ///< Maximum frames per second for rendering | |||
Int m_logicTimeScaleFPS; ///< Maximum frames per second for logic time scale |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be better to rename m_maxFPS
to make it more relevant to the rendering FPS.
m_maxRenderFPS
for example.
For the logic one, it would be better to have the naming match the rendering.
m_maxLogicFPS
etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not intent to rename m_maxFPS
for this change to have a bit less diff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
m_maxLogicFPS
is not the correct terminology for this. Logic FPS is what we currently refer to as enum LOGICFRAMES_PER_SECOND=30.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
m_maxLogicFPS
is not the correct terminology for this. Logic FPS is what we currently refer to as enum LOGICFRAMES_PER_SECOND=30.
It's the currently set max logic frame rate, LOGICFRAMES_PER_SECOND
is the default maximum value. But since we can / need to be able to vary the current max logic frame rate, it makes sense to call it that for the variable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
m_logicTimeScaleFPS is conceptually not equivalent to LOGICFRAMES_PER_SECOND or m_maxLogicFPS. It effectively is a ratio that scales the logic fps.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You ask me to rename it to m_maxLogicFPS
but I am telling you this is not the right name for it. Originally I used this exact name for it, until I realized it is misleading because it would be pretty much identical to LOGICFRAMES_PER_SECOND but are not the same thing. This is why I called it Logic Time Scale.
Currently Logic Time Scale is capped by the Render Update. We could perhaps also uncap it and make it a substitute for fast forwarding globally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not misleading though, i think you are putting too much emphasis on what LOGICFRAMES_PER_SECOND
means compared to what it actually is meant to be.
LOGICFRAMES_PER_SECOND
is the default maximum logic frame rate during normal gameplay etc. It's basically a value used for default configuration and normal configuration.
While your m_logicTimeScaleFps
is the max logic FPS that is being used within the game at runtime. Which can vary to allow fast gameplay mode in skirmish or within mod maps etc.
Both values are related but mean different things.
Logic tick rate being capped by the rendering is fine, but that's a different problem overall. The logic tick rate does not need to exceed the rendering rate and probably never should. But varying the max logic rate implements the fast forward functionality, so of course the render rate has to increase if the logic rate was to exceed it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thing is, when we make LOGICFRAMES_PER_SECOND configurable, then what will be its name? Given your name proposal, it would end up being something like:
Int m_logicFPS;
Int m_maxLogicFPS;
I disagree with giving these 2 things the same name.
This will be better:
Int m_logicFPS;
Int m_logicTimeScaleFPS;
The logic tick rate does not need to exceed the rendering rate and probably never should.
It does so in the original game, during fast forwarding. I think it is fine to do that. I can explore this in a follow up change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thing is, when we make LOGICFRAMES_PER_SECOND configurable, then what will be its name?
At that point it would be like with any other configurable variable. we have the config handling set Int m_maxLogicFPS;
at startup etc. Or it uses the constant LOGICFRAMES_PER_SECOND
as the default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I expect it will be possible to change LOGICFRAMES_PER_SECOND at runtime to any value above 0.
if ( ! TheGlobalData->m_TiVOFastMode ) | ||
#else //always allow this cheatkey if we're in a replaygame. | ||
if ( ! (TheGlobalData->m_TiVOFastMode && TheGameLogic->isInReplayGame())) | ||
if ( ! TheGlobalData->m_TiVOFastMode ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does fast forwarding actually work in replays?
The logic here looks like it does not affect the logic rate so would actually break replay fast forwarding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Last time I checked it worked, but I can retest.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fine in this update then if you have the logic frame rate limiting disabled by default.
But once it does get enabled it will break fast forwarding at this point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tested with capped and uncapped logic time scale and fast forward worked.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made a pass on the fast forward implementation and made sure that the new code does not break it. I tested and it worked. The plan forward is to replace the fast forward code with the new logic time scale function when the logic update can exceed the render update. I hope it won't be that hard to do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think as long as the render logic is not being locked then the fast forward here should still function okay.
it's just when people decide to lock the logic but unlock the rendering, the tivo_mode
variable might need checking as well in the logic rate limiting to disable / ignore the limiting when it is active it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't quite follow. Do I need to do anything?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't quite follow. Do I need to do anything?
Ah i see you catored for it in the update for the logic
Bool fastForward = !TheGameLogic->isGamePaused() && TheGlobalData->m_TiVOFastMode && TheGameLogic->isInReplayGame();
#endif
if (fastForward)
{
TheGameClient->step();
TheGameLogic->UPDATE();
}
I didn't notice that yesterday so might have been what you just added.
But this could be made simpler by appending the fastForward check to the if statement above it were you check to see if the locking is enabled and the timestep has been reached.
so we either go if we are fastforwarding or are enabled and the timestep has been met.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I added it today.
But this could be made simpler
Fixed
No. This change does not intent to touch it yet as described in the pull request description. For now, the new limits are only accessible with the new key mappings and the game still applies its fps limits as it always did. The reason for that is, this change is already big enough and I do not want to risk breaking anything yet. It is a more careful rollout. |
So this is a breaking change then as it breaks the game speed adjustment in skirmish. |
Can you elaborate? When I tested, by default, it did not change behavior. |
The game speed adjustment is there to allow the game logic to tick faster than 30 frames, but this was tied to FPS at the same time in the original implementation. it was never about allowing a higher framerate. If you are only increasing render FPS limit then the game logic won't be running faster for the faster game speed. |
It does, because Logic Time Scale FPS is disabled by default. Unless I made a mistake or the new key mappings are pressed in game, the default game behaviour should be the exact same. I suggest to give this a test in game. |
GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp
Outdated
Show resolved
Hide resolved
Ah i see now, i thought you had the logic frame rate locking always enabled. |
Are the key mappings hard coded? |
The default key mappings are. They can be overriden in CommandMap.ini |
It would be good to investigate how this change interacts with already existing ways to change game speed and FPS. There are scripts that do very similar things as this PR. This change has the potential to break every single script in all maps in the history of the game if we're not careful. Investigation of internal script timers, frame counters and more is probably needed to verify this doesn't break anything. Changing scripts in general should be done with utmost consideration. Additionally, I can imagine that in some cases the game logic should not be increased beyond a specific value. Examples are cinematic intros in campaign maps (eg. ZH USA 01), or maps with many audio events like Generals' Challenge maps. In such cases the logic should have a custom cap specifically tied to that map, likely specified in the map.ini. |
1036d47
to
a9147d6
Compare
The default behavior of scripts is not changed. |
a9147d6
to
a0d1f04
Compare
a0d1f04
to
9faaab8
Compare
9faaab8
to
4bb9f4e
Compare
@@ -408,7 +413,7 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage | |||
// The scaling is based on the current logic rate, this provides a consistent scroll speed at all GameClient FPS | |||
// This also fixes scrolling within replays when fast forwarding due to the uncapped FPS | |||
// When the FPS is in excess of the expected frame rate, the ratio will reduce the offset of the cameras movement | |||
const Real logicToFpsRatio = TheGlobalData->m_framesPerSecondLimit / TheDisplay->getCurrentFPS(); | |||
const Real logicToFpsRatio = 30.0f / TheGameEngine->getUpdateFps(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not correct, the value being divided by the FPS needs to be whatever the current logic rate is otherwise the scrolling will be inconsistent during fast forward and fast game speeds.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tested it and it works correctly.
Using TheGlobalData->m_framesPerSecondLimit
is not correct because the fps setting in GameData.ini or -fps command line argument should not affect the scroll speed.
True, but the fact remains that some scripts might interact with render frames while others interact with logic frames. Now that they are decoupled people with different settings will get different results (and potentially get mismatches if they play COOP, AOD, or even multiplayer skirmish. That should not be. It should be checked where this could happen. |
The Network logic update is unchanged. No mismatch. |
Merge with Rebase
This change has several commits to fix and improve several aspects in regards to the render frame time in relation to the logic time step.
The frame limiter has been reimplemented with a high accuracy counter for more accurate FPS capping.
The following systems are now decoupled from the render update:
There are way more things that could be decoupled but for starters this appears to be good enough and usable.
To control the Logic Time Scale FPS and Render FPS the following default key mapping are added:
Changes to the FPS are currently NOT saved to Options.ini and the game still applies its frame rate adjustements in Skirmish, Campaign and similar as usual. By default, the game behaves as originally and this feature is currently entirely opt-in with the key mappings.
TODO